module CPUDefs where

import Data.Int
import Data.Word
import Data.STRef
import Data.Array.ST
import Control.Monad.ST
import Control.Monad.Reader
--import GHC.Arr

data CPU = CPU {
   aReg     :: Operand,
   xReg     :: Operand,
   yReg     :: Operand,
   sp       :: Word8,
   pc       :: Address,
   status   :: Status,
   inter    :: Interrupt
}

data Interrupt = None | BRK | NMI | RST
data Status = Status { 
    c  :: Bool, z  :: Bool, i  :: Bool, d  :: Bool, 
    b  :: Bool, v  :: Bool, n  :: Bool
} deriving Show

type NES s a = ReaderT (CPUMemory s,STRef s CPU) (ST s) a
type MemArray s = STUArray s Address Operand
data CPUMemory s = Memory {
    low         :: MemArray s,
    cpushared   :: MemArray s,
    high        :: MemArray s
}

-- additional type declarations
type Operand    = Int8
type OPCode     = Int8
type Address    = Word16
data Index      = X | Y

-- Before = X, After = Y (apparently)
data Indexed = Before | After
data AddrMode = 
     ZeroPage (Maybe Index) Operand
   | Absolute (Maybe Index) Address
   | Relative Operand
   | Indirect Address
   | Indexed Indexed Operand

instance Show CPU where
    show cpu = " A " ++ show (aReg cpu)
            ++ " | X " ++ show (xReg cpu)
            ++ " | Y " ++ show (yReg cpu)
            ++ " | PC " ++ show (pc cpu)
            ++ " | SP " ++ show (sp cpu)

-- Interface to change memory (IArray interface is nicer that MArray)
(!) :: MemArray s -> Address -> NES s Operand
mem ! addr = lift $ readArray mem addr

(//) :: MemArray s -> (Address,Operand) -> NES s ()
mem // (addr,op) = lift $ writeArray mem addr op

-- Operating on CPU as if it were in the state monad
get :: NES s CPU
get = asks snd >>= lift . readSTRef

gets :: (CPU -> a) -> NES s a
gets f = do
   cpuref <- asks snd
   cpu    <- lift $ readSTRef cpuref
   return $ f cpu

modify :: (CPU -> CPU) -> NES s ()
modify f = do
    cpuref <- asks snd
    lift $ modifySTRef cpuref f

put :: CPU -> NES s ()
put cpu = do
    ref <- asks snd
    lift $ writeSTRef ref cpu

baseSP :: Address
baseSP = 0x0100

